#include "flow_service.h"
#include "context.h"
#include "streamdata.h"
#include "log.h"
#include "util.h"
#include "apiordercache.h"
#include "1000_flow.pb.h"
#include "9100_agency_api.pb.h"


void FlowService::OnBet(std::int32_t result, std::uint32_t uid, const std::string& provider, std::uint32_t agencyid, std::uint32_t gameid, 
    std::uint64_t cycle, std::uint64_t orderid, std::uint64_t optime, std::int64_t balance, std::int64_t bet, std::int64_t preserve)
{
    switch (result)
    {
    case agency_api::ErrorCode::Success:
    case agency_api::ErrorCode::RespTimeout:
        RecordBet(result, uid, provider, agencyid, gameid, cycle, orderid, optime, balance, bet, preserve);
        break;
    default:
    {
        if (ApiOrderCache::Instance()->CheckCancleBet(orderid))
        {
            // 下注失败 + 有撤销记录, 则 增加流水上报
            RecordBet(result, uid, provider, agencyid, gameid, cycle, orderid, optime, balance, bet, preserve);
            //清理缓存
            // log_debug("ClearCancleBet, uid:%u,gameid:%u,cycle:%llu,orderid:%llu", uid, gameid, cycle, orderid);
            ApiOrderCache::Instance()->ClearCancleBet(orderid);
        }
        else 
        {
            // 缓存 下注记录
            ApiOrderCache::Data op_data; 
            op_data.result              = result               ;
            op_data.uid                 = uid                  ;
            op_data.provider            = provider             ;
            op_data.agencyid            = agencyid             ;
            op_data.gameid              = gameid               ;
            op_data.cycle               = cycle                ;
            op_data.orderid             = orderid              ;
            op_data.optime              = optime               ;
            op_data.balance             = balance              ;
            op_data.bet                 = bet                  ;
            op_data.preserve            = preserve             ;
            op_data.expire_time         = CTools::GetUnixTime() + 60;
            // log_debug("CacheBetFailed, uid:%u,gameid:%u,cycle:%llu,orderid:%llu", uid, gameid, cycle, orderid);
            ApiOrderCache::Instance()->CacheBetFailed(orderid, std::move(op_data));
        }
        return;
    }
    }
}
void FlowService::OnWin(std::int32_t result, std::uint32_t uid, const std::string& provider, std::uint32_t agencyid, std::uint32_t gameid, 
        std::uint64_t cycle, std::uint64_t orderid, std::uint64_t optime, std::int64_t balance, std::int64_t winlose, std::int64_t bet, std::int64_t preserve)
{
    RecordWin(result, uid, provider, agencyid, gameid, cycle, orderid, optime, balance, winlose, bet, preserve);
}
void FlowService::OnBetAndWin(std::int32_t result, std::uint32_t uid, const std::string& provider, std::uint32_t agencyid, std::uint32_t gameid, 
        std::uint64_t cycle, std::uint64_t orderid, std::uint64_t optime, std::int64_t balance, std::int64_t bet, std::int64_t winlose)
{
    switch (result)
    {
    case agency_api::ErrorCode::Success:
    case agency_api::ErrorCode::RespTimeout:
        RecordBetAndWin(result, uid, provider, agencyid, gameid, cycle, orderid, optime, balance, bet, winlose);
        break;
    default:
    {
        if (ApiOrderCache::Instance()->CheckCancleBetAndWin(orderid))
        {
            // 操作失败 + 有撤销记录, 则 增加流水上报
            RecordBetAndWin(result, uid, provider, agencyid, gameid, cycle, orderid, optime, balance, bet, winlose);
            //清理缓存
            // log_debug("ClearCancleBetAndWin, uid:%u,gameid:%u,cycle:%llu,orderid:%llu", uid, gameid, cycle, orderid);
            ApiOrderCache::Instance()->ClearCancleBetAndWin(orderid);
        }
        else
        {
            // 缓存 操作记录
            ApiOrderCache::Data op_data; 
            op_data.result              = result               ;
            op_data.uid                 = uid                  ;
            op_data.provider            = provider             ;
            op_data.agencyid            = agencyid             ;
            op_data.gameid              = gameid               ;
            op_data.cycle               = cycle                ;
            op_data.orderid             = orderid              ;
            op_data.optime              = optime               ;
            op_data.balance             = balance              ;
            op_data.bet                 = bet                  ;
            op_data.winlose             = winlose              ;
            op_data.expire_time         = CTools::GetUnixTime() + 60;
            // log_debug("CacheBetAndWinFailed, uid:%u,gameid:%u,cycle:%llu,orderid:%llu", uid, gameid, cycle, orderid);
            ApiOrderCache::Instance()->CacheBetAndWinFailed(orderid, std::move(op_data));
        }
    }
    }

}
void FlowService::OnCancleBet(std::int32_t result, std::uint32_t uid, const std::string& provider, std::uint32_t agencyid, std::uint32_t gameid, 
        std::uint64_t cycle, std::uint64_t orderid, std::uint64_t optime, std::int64_t balance, std::int64_t bet, std::int64_t preserve, std::uint64_t associatedorder)
{
    ApiOrderCache::Data* op_data = ApiOrderCache::Instance()->CheckBetFailed(associatedorder); 
    if (op_data != nullptr)
    {
        // 记录 下注失败
        RecordBet(op_data->result, op_data->uid, op_data->provider, 
            op_data->agencyid, op_data->gameid, op_data->cycle, op_data->orderid, op_data->optime, 
            op_data->balance, op_data->bet, op_data->preserve);
        // 记录 取消操作
        RecordCancleBet(result, uid, provider, agencyid, gameid, cycle, orderid, optime, balance, bet, preserve, associatedorder);
        //清理缓存
        // log_debug("ClearBetFailed, uid:%u,gameid:%u,cycle:%llu,orderid:%llu", op_data->uid, op_data->gameid, op_data->cycle, op_data->orderid);
        ApiOrderCache::Instance()->ClearBetFailed(associatedorder);
    }
    else
    {
        // 缓存 取消记录
        // log_debug("CacheCancleBet, uid:%u,gameid:%u,cycle:%llu,orderid:%llu,associatedorder:%llu", uid, gameid, cycle, orderid, associatedorder);
        ApiOrderCache::Instance()->CacheCancleBet(associatedorder, CTools::GetUnixTime() + 60);

        RecordCancleBet(result, uid, provider, agencyid, gameid, cycle, orderid, optime, balance, bet, preserve, associatedorder);
    }
}
void FlowService::OnCancleBetAndWin(std::int32_t result, std::uint32_t uid, const std::string& provider, std::uint32_t agencyid, std::uint32_t gameid, 
        std::uint64_t cycle, std::uint64_t orderid, std::uint64_t optime, std::int64_t balance, std::int64_t bet, std::int64_t winlose, std::uint64_t associatedorder)
{
    ApiOrderCache::Data* op_data = ApiOrderCache::Instance()->CheckBetAndWinFailed(associatedorder); 
    if (op_data != nullptr)
    {
        // 有下注记录, 则 增加流水上报
        RecordBetAndWin(op_data->result, op_data->uid, op_data->provider, 
            op_data->agencyid, op_data->gameid, op_data->cycle, op_data->orderid, op_data->optime, 
            op_data->balance, op_data->bet, op_data->winlose);
        // 缓存 取消记录
        RecordCancleBetAndWin(result, uid, provider, agencyid, gameid, cycle, orderid, optime, balance, bet, winlose, associatedorder);
        //清理缓存
        // log_debug("ClearBetAndWinFailed, uid:%u,gameid:%u,cycle:%llu,orderid:%llu", op_data->uid, op_data->gameid, op_data->cycle, op_data->orderid);
        ApiOrderCache::Instance()->ClearBetAndWinFailed(associatedorder);
    }
    else
    {
        // 缓存 取消记录
        // log_debug("CacheCancleBetAndWin, uid:%u,gameid:%u,cycle:%llu,orderid:%llu,associatedorder:%llu", uid, gameid, cycle, orderid, associatedorder);
        ApiOrderCache::Instance()->CacheCancleBetAndWin(associatedorder, CTools::GetUnixTime() + 60);

        RecordCancleBetAndWin(result, uid, provider, agencyid, gameid, cycle, orderid, optime, balance, bet, winlose, associatedorder);
    }
}

void FlowService::OnReward(std::int32_t result, std::uint32_t uid, const std::string& provider, std::uint32_t agencyid, std::uint32_t gameid, 
        std::uint32_t activityid, std::uint64_t orderid, std::uint64_t optime, std::int64_t balance, std::int64_t amount)
{
    RecordReward(result, uid, provider, agencyid, gameid, activityid, orderid, optime, balance, amount);
}

void FlowService::RecordBet(std::int32_t result, std::uint32_t uid, const std::string& provider, std::uint32_t agencyid, std::uint32_t gameid, 
        std::uint64_t cycle, std::uint64_t orderid, std::uint64_t optime, std::int64_t balance, std::int64_t bet, std::int64_t preserve)
{
    flow::FlowPush flow_push;
    if (preserve > 0)
    {
        flow::Flow* flow = flow_push.add_flow();
        flow->set_result(result);
        flow->set_uid(uid);
        flow->mutable_op()->set_act(flow::ACT_FREEZE);
        flow->mutable_op()->set_delt(-preserve);
        flow->mutable_gameinfo()->set_provider(provider);
        flow->mutable_gameinfo()->set_agencyid(agencyid);
        flow->mutable_gameinfo()->set_gameid(gameid);
        flow->mutable_gameinfo()->set_cycle(cycle);
        flow->mutable_gameinfo()->set_orderid(orderid);
        flow->set_optime(optime);
        flow->set_balance(balance);
    }
    else if (bet > 0)
    {
        flow::Flow* flow = flow_push.add_flow();
        flow->set_result(result);
        flow->set_uid(uid);
        flow->mutable_op()->set_act(flow::ACT_BET);
        flow->mutable_op()->set_delt(-bet);
        flow->mutable_gameinfo()->set_provider(provider);
        flow->mutable_gameinfo()->set_agencyid(agencyid);
        flow->mutable_gameinfo()->set_gameid(gameid);
        flow->mutable_gameinfo()->set_cycle(cycle);
        flow->mutable_gameinfo()->set_orderid(orderid);
        flow->set_optime(optime);
        flow->set_balance(balance);
    }

    log_debug("flow_push:%s", flow_push.ShortDebugString().c_str());
    Ctx.host->MtSendtoSrv(flow::FLOW_CMD_FLOW_PUSH, SERVER_TYPE_FLOW, &flow_push, uid);
}
void FlowService::RecordWin(std::int32_t result, std::uint32_t uid, const std::string& provider, std::uint32_t agencyid, std::uint32_t gameid, 
        std::uint64_t cycle, std::uint64_t orderid, std::uint64_t optime, std::int64_t balance, std::int64_t winlose, std::int64_t bet, std::int64_t preserve)
{
    flow::FlowPush flow_push;
    if (winlose >= 0)
    {
        flow::Flow* flow = flow_push.add_flow();
        flow->set_result(result);
        flow->set_uid(uid);
        flow->mutable_op()->set_act(flow::ACT_WINLOST);
        flow->mutable_op()->set_delt(winlose);
        flow->mutable_gameinfo()->set_provider(provider);
        flow->mutable_gameinfo()->set_agencyid(agencyid);
        flow->mutable_gameinfo()->set_gameid(gameid);
        flow->mutable_gameinfo()->set_cycle(cycle);
        flow->mutable_gameinfo()->set_orderid(orderid);
        flow->set_optime(optime);
        flow->set_balance(balance);
    }
    if (preserve > 0)
    {
        flow::Flow* flow = flow_push.add_flow();
        flow->set_result(result);
        flow->set_uid(uid);
        flow->mutable_op()->set_act(flow::ACT_UNFREEZE);
        flow->mutable_op()->set_delt(preserve);
        flow->mutable_gameinfo()->set_provider(provider);
        flow->mutable_gameinfo()->set_agencyid(agencyid);
        flow->mutable_gameinfo()->set_gameid(gameid);
        flow->mutable_gameinfo()->set_cycle(cycle);
        flow->mutable_gameinfo()->set_orderid(orderid);
        flow->set_optime(optime);
        flow->set_balance(balance);
            
        if (bet > 0)
        {
            flow::Flow* flow = flow_push.add_flow();
            flow->set_result(result);
            flow->set_uid(uid);
            flow->mutable_op()->set_act(flow::ACT_BET);
            flow->mutable_op()->set_delt(-bet);
            flow->mutable_gameinfo()->set_provider(provider);
            flow->mutable_gameinfo()->set_agencyid(agencyid);
            flow->mutable_gameinfo()->set_gameid(gameid);
            flow->mutable_gameinfo()->set_cycle(cycle);
            flow->mutable_gameinfo()->set_orderid(orderid);
            flow->set_optime(optime);
            flow->set_balance(balance);
        }
    }

    log_debug("flow_push:%s", flow_push.ShortDebugString().c_str());
    Ctx.host->MtSendtoSrv(flow::FLOW_CMD_FLOW_PUSH, SERVER_TYPE_FLOW, &flow_push, uid);
}
void FlowService::RecordBetAndWin(std::int32_t result, std::uint32_t uid, const std::string& provider, std::uint32_t agencyid, std::uint32_t gameid, 
        std::uint64_t cycle, std::uint64_t orderid, std::uint64_t optime, std::int64_t balance, std::int64_t bet, std::int64_t winlose)
{
    flow::FlowPush flow_push;
    if (bet > 0)
    {
        flow::Flow* flow = flow_push.add_flow();
        flow->set_result(result);
        flow->set_uid(uid);
        flow->mutable_op()->set_act(flow::ACT_BET);
        flow->mutable_op()->set_delt(-bet);
        flow->mutable_gameinfo()->set_provider(provider);
        flow->mutable_gameinfo()->set_agencyid(agencyid);
        flow->mutable_gameinfo()->set_gameid(gameid);
        flow->mutable_gameinfo()->set_cycle(cycle);
        flow->mutable_gameinfo()->set_orderid(orderid);
        flow->set_optime(optime);
        flow->set_balance(balance);
    }
    if (winlose >= 0)
    {
        flow::Flow* flow = flow_push.add_flow();
        flow->set_result(result);
        flow->set_uid(uid);
        flow->mutable_op()->set_act(flow::ACT_WINLOST);
        flow->mutable_op()->set_delt(winlose);
        flow->mutable_gameinfo()->set_provider(provider);
        flow->mutable_gameinfo()->set_agencyid(agencyid);
        flow->mutable_gameinfo()->set_gameid(gameid);
        flow->mutable_gameinfo()->set_cycle(cycle);
        flow->mutable_gameinfo()->set_orderid(orderid);
        flow->set_optime(optime);
        flow->set_balance(balance);
    }

    log_debug("flow_push:%s", flow_push.ShortDebugString().c_str());
    Ctx.host->MtSendtoSrv(flow::FLOW_CMD_FLOW_PUSH, SERVER_TYPE_FLOW, &flow_push, uid);
}
void FlowService::RecordCancleBet(std::int32_t result, std::uint32_t uid, const std::string& provider, std::uint32_t agencyid, std::uint32_t gameid, 
        std::uint64_t cycle, std::uint64_t orderid, std::uint64_t optime, std::int64_t balance, std::int64_t bet, std::int64_t preserve, std::uint64_t associatedorder)
{
    flow::FlowPush flow_push;
    if (preserve > 0)
    {
        flow::Flow* flow = flow_push.add_flow();
        flow->set_result(result);
        flow->set_uid(uid);
        flow->mutable_op()->set_act(flow::ACT_UNFREEZE);
        flow->mutable_op()->set_delt(preserve);
        flow->mutable_gameinfo()->set_provider(provider);
        flow->mutable_gameinfo()->set_agencyid(agencyid);
        flow->mutable_gameinfo()->set_gameid(gameid);
        flow->mutable_gameinfo()->set_cycle(cycle);
        flow->mutable_gameinfo()->set_orderid(orderid);
        flow->mutable_gameinfo()->set_associatedorder(associatedorder);
        flow->set_optime(optime);
        flow->set_balance(balance);
    }
    else if (bet > 0)
    {
        flow::Flow* flow = flow_push.add_flow();
        flow->set_result(result);
        flow->set_uid(uid);
        flow->mutable_op()->set_act(flow::ACT_CANCEL_BET);
        flow->mutable_op()->set_delt(bet);
        flow->mutable_gameinfo()->set_provider(provider);
        flow->mutable_gameinfo()->set_agencyid(agencyid);
        flow->mutable_gameinfo()->set_gameid(gameid);
        flow->mutable_gameinfo()->set_cycle(cycle);
        flow->mutable_gameinfo()->set_orderid(orderid);
        flow->mutable_gameinfo()->set_associatedorder(associatedorder);
        flow->set_optime(optime);
        flow->set_balance(balance);
    }

    log_debug("flow_push:%s", flow_push.ShortDebugString().c_str());
    Ctx.host->MtSendtoSrv(flow::FLOW_CMD_FLOW_PUSH, SERVER_TYPE_FLOW, &flow_push, uid);
}
void FlowService::RecordCancleBetAndWin(std::int32_t result, std::uint32_t uid, const std::string& provider, std::uint32_t agencyid, std::uint32_t gameid, 
        std::uint64_t cycle, std::uint64_t orderid, std::uint64_t optime, std::int64_t balance, std::int64_t bet, std::int64_t winlose, std::uint64_t associatedorder)
{
    flow::FlowPush flow_push;
    if (bet > 0)
    {
        flow::Flow* flow = flow_push.add_flow();
        flow->set_result(result);
        flow->set_uid(uid);
        flow->mutable_op()->set_act(flow::ACT_CANCEL_BET);
        flow->mutable_op()->set_delt(bet);
        flow->mutable_gameinfo()->set_provider(provider);
        flow->mutable_gameinfo()->set_agencyid(agencyid);
        flow->mutable_gameinfo()->set_gameid(gameid);
        flow->mutable_gameinfo()->set_cycle(cycle);
        flow->mutable_gameinfo()->set_orderid(orderid);
        flow->mutable_gameinfo()->set_associatedorder(associatedorder);
        flow->set_optime(optime);
        flow->set_balance(balance);
    }
    if (winlose >= 0)
    {
        flow::Flow* flow = flow_push.add_flow();
        flow->set_result(result);
        flow->set_uid(uid);
        flow->mutable_op()->set_act(flow::ACT_CANCEL_WINLOST);
        flow->mutable_op()->set_delt(-winlose);
        flow->mutable_gameinfo()->set_provider(provider);
        flow->mutable_gameinfo()->set_agencyid(agencyid);
        flow->mutable_gameinfo()->set_gameid(gameid);
        flow->mutable_gameinfo()->set_cycle(cycle);
        flow->mutable_gameinfo()->set_orderid(orderid);
        flow->mutable_gameinfo()->set_associatedorder(associatedorder);
        flow->set_optime(optime);
        flow->set_balance(balance);
    }

    log_debug("flow_push:%s", flow_push.ShortDebugString().c_str());
    Ctx.host->MtSendtoSrv(flow::FLOW_CMD_FLOW_PUSH, SERVER_TYPE_FLOW, &flow_push, uid);
}

void FlowService::RecordReward(std::int32_t result, std::uint32_t uid, const std::string& provider, std::uint32_t agencyid, std::uint32_t gameid, 
        std::uint32_t activityid, std::uint64_t orderid, std::uint64_t optime, std::int64_t balance, std::int64_t amount)
{
    flow::FlowPush flow_push;
    if (amount > 0)
    {
        flow::Flow* flow = flow_push.add_flow();
        flow->set_result(result);
        flow->set_uid(uid);
        flow->mutable_op()->set_act(flow::ACT_GAME_REWARD);
        flow->mutable_op()->set_delt(amount);
        flow->mutable_gameinfo()->set_provider(provider);
        flow->mutable_gameinfo()->set_agencyid(agencyid);
        flow->mutable_gameinfo()->set_gameid(gameid);
        flow->mutable_gameinfo()->set_cycle(activityid);
        flow->mutable_gameinfo()->set_orderid(orderid);
        flow->set_optime(optime);
        flow->set_balance(balance);
    }
    
    log_debug("flow_push:%s", flow_push.ShortDebugString().c_str());
    Ctx.host->MtSendtoSrv(flow::FLOW_CMD_FLOW_PUSH, SERVER_TYPE_FLOW, &flow_push, uid);
}











